package ua.org.nuos.sdms.middle.testutils;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by IntelliJ IDEA.
 * User: dio
 * Date: 11.10.11
 * Time: 19:34
 * To change this template use File | Settings | File Templates.
 */
public abstract class AbstractDaoTestCase<T> {

    protected static final String EM_FIELD_NAME = "em";
    protected static final String INIT_METHOD_NAME = "init";

    protected static DBUtil dbUtil;
    protected static EntityManagerFactory emf;
    protected EntityManager em;
    protected T bean;

    protected abstract Class<T> getBeanClass();

    protected void beforeTest() throws Exception {
    }

    @BeforeClass
    public static void createEntityManagerFactory() throws IOException {
        dbUtil = new DBUtil();
        emf = Persistence.createEntityManagerFactory("testSDMS");
    }

    @AfterClass
    public static void closeEntityManagerFactory() {
        dbUtil.closeConnection();
        emf.close();
    }

    @Before
    public void initDataBase() {
        dbUtil.setUpDatabase(new String[]{
                "group.yml",
                "user.yml",
                "email_verification.yml",
                "user_role.yml",
                "user_to_group.yml",
                "teacher.yml"});
    }

    @Before
    public void beginTransaction() throws Exception {
        em = emf.createEntityManager();
        em.getTransaction().begin();
        bean = getBeanClass().newInstance();
        injectField(bean, EM_FIELD_NAME, em);
        fireMethod(bean, INIT_METHOD_NAME);
        beforeTest();
    }

    @After
    public void rollbackTransaction() {
        if (em != null) {
            if (em.getTransaction().isActive()) {
                em.clear();
                em.getTransaction().commit();
            }
            if (em.isOpen()) {
                em.close();
            }
        }
        bean = null;
        em = null;
    }

    protected void injectField(Object o, String fieldName, Object fieldValue) throws IllegalAccessException {
        Class beanClass = o.getClass();
        try {
            Field field = beanClass.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(o, fieldValue);
        } catch (NoSuchFieldException e) {
            System.out.printf("no field with name \"%s\" in class \"%s\"\n", fieldName, o.getClass().getName());
        }
    }

    protected void fireMethod(Object o, String methodName) {
        try {
            Method method = o.getClass().getDeclaredMethod(methodName);
            method.setAccessible(true);
            method.invoke(o);
        } catch (Exception ex) {
            System.out.printf("no method with name \"%s\" in class \"%s\"\n", methodName, o.getClass().getName());
        }
    }
}
